# -*- coding: utf-8 -*-

import logging
_logger = logging.getLogger(__name__)

from threading import Thread, Lock
import json
import time

try:
    from queue import Queue, Empty
except ImportError:
    from Queue import Queue, Empty  # pylint: disable=deprecated-module

try:
    import paho.mqtt.client as mqtt

except (ImportError, IOError) as err:
    _logger.debug(err)

from functools import wraps

def singleton(cls):
    instances = {}

    @wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class MQTT(Thread):
    def __init__(self, client_id, userdata):
        Thread.__init__(self)
        self.queue = Queue()
        self.lock = Lock()
        self.client = mqtt.Client(client_id, userdata=userdata)
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.on_publish = self.on_publish
        self.client.on_subscribe = self.on_subscribe

    def lockedstart(self):
        with self.lock:
            if not self.isAlive():
                self.daemon = True
                self.start()

    def push_task(self, task, topic=None, data=None, qos=None):
        if not qos:
            qos = 0
        self.lockedstart()
        self.queue.put((time.time(), task, topic, data, qos))

    def run(self):
        while True:
            try:
                timestamp, task, topic, data, qos = self.queue.get(True)
                if task == 'connect':
                    self.connect(data)
                elif task == "start":
                    self.start_mtqq()
                elif task == "stop":
                    self.stop_mtqq()
                elif task == 'subscribe':
                    self.subscribe(topic, qos)
                elif task == 'publish':
                    self.publish(topic, data, qos)
            except Exception as e:
                _logger.error('Error: %s' % str(e))

    def start_mtqq(self):
        self.client.loop_start()
        _logger.info('MQTT Interface Started')

    def stop_mtqq(self):
        self.client.loop_stop()
        _logger.info('MQTT Interface Stop')

    # data is a dictionary within host port and ttl
    def connect(self, data):
        _logger.info("INFO: to connect. %s" % data)
        self.client.connect(data['host'], data['port'], data['ttl'])
        _logger.info("INFO: to connect. ok" )

    # The callback for when the client receives a CONNACK response from the server.
    def on_connect(self, client, userdata, flags, rc):
        _logger.info("Connected with result code " + str(rc))

    def subscribe(self, topic, qos=0):
        _logger.info('MQTT subscribe %s' % topic)
        self.client.subscribe(topic, qos)

    def on_subscribe(self, client, userdata, mid, granted_qos):
        _logger.info('MQTT on_subscribe %s, %s, %s' % (userdata , mid, granted_qos))

    # The callback for when a PUBLISH message is received from the server.
    def on_message(self, client, userdata, msg):
        _logger.info("INFO: recieve a message!")
        _logger.info("Message: " + msg.topic + " " + str(msg.payload))

    def publish(self, topic,  data, qos=0):
        _logger.info('MQTT publish %s, %s' % (topic, data))
        self.client.publish(topic, str(json.dumps(data)).strip().strip('"'), qos)

    def on_publish(self, client, userdata , mid):
        _logger.info('MQTT on_publish %s, %s, %s' % (client, userdata , mid))


def create_interface(config=None):
    if not config:
        config = {}

    client_id = config.get('client_id', None)
    userdata = config.get('userdata')
    interface = MQTT(client_id, userdata)

    data = {
        'host': config.get('host', 'localhost'),
        'port': config.get('port', 1883),
        'ttl': config.get('ttl', 60),
    }

    interface.push_task('start')
    interface.push_task('connect', data=data)
    time.sleep(2)
    return interface


MQTT_config = {
    # 'client_id': 'odoo_server',
    # 'userdata': {'db': ''},
    # 'host': "localhost",
    # 'host': "192.168.56.101",
    # 'port': 1883,
    # 'ttl': 60

}

# interface = create_interface(MQTT_config)
